home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 24 / Mac Magazin and MacEasy Magazine CD - Issue 24.iso / Wissenschaft & Technik / Sys Environment (PPC) Dev ƒ / Source / sysEnv.cpp < prev   
C/C++ Source or Header  |  1996-08-12  |  20KB  |  670 lines

  1. //sysEnv.c ©1996 Brian Bergstrand 07/16/96
  2.  
  3. #include <stdio.h>
  4. #include "sysEnv.h"
  5. #include "machines.h"
  6. #include "systems.h"
  7.  
  8. //globals
  9. AppGlobals *global = new AppGlobals;//create an instance and allocate memory  
  10.   
  11. //main function - returns nothing
  12. void main (void)
  13. {
  14.   int whichCursor;
  15.   whichCursor = kWatchCursor;
  16.   SwitchCursor (&whichCursor);//sets the cursor to the watch
  17.   
  18.   InitToolBox();//Intialize the ToolBox
  19.   
  20.   //test for gestalt, don't really need to do this, but Apple still recommends it
  21.   long response;
  22.   OSErr myErr = Gestalt (gestaltVersion, &response);
  23.   if (myErr)//if gestalt is not present
  24.     HandleError (2, true, 0L);//call our error handling code
  25.     
  26.   MenuBarInit();
  27.   
  28.   SetCursor (&qd.arrow);//sets the cursor back to the arrow
  29.   
  30.   HandleEnvDialog();//show the dialog
  31.   EventLoop();//then start the main event loop
  32. }
  33.  
  34. //SwitchCursor function - returns nothing
  35. void SwitchCursor (int *whichCursor)
  36. {
  37.   Cursor myCursor;
  38.   CursHandle cursorH;
  39.   
  40.   if (*whichCursor==kWatchCursor)//if the cursor choice = watch
  41.     cursorH = GetCursor (watchCursor);//get a handle to the watch cursor
  42.     
  43.   HLock ((Handle) cursorH);//lock the handle
  44.   myCursor = **cursorH;
  45.   HUnlock ((Handle) cursorH);//unlock the handle  
  46.   SetCursor (&myCursor);//set the cursor
  47. }    
  48.                 
  49. //ToolBoxInit function - returns nothing
  50. void InitToolBox (void)
  51. {//intialize all of the TB managers
  52.   InitGraf (&qd.thePort);
  53.   InitFonts();
  54.   InitWindows();
  55.   InitMenus();
  56.   TEInit();
  57.   InitDialogs(0L);
  58.   InitCursor();
  59.   
  60.   MaxApplZone();//we can use this now, but Mac OS 8 will break with this call
  61.   FlushEvents(everyEvent, 0);//flush all cued events
  62.   MoreMasters();//we can use this now, but Mac OS 8 will break with this call
  63. }
  64.  
  65. //MenuBarInit function - returns nothing
  66. void MenuBarInit (void)
  67. {
  68.   Handle    menuBar;
  69.   MenuHandle    menu;
  70.   
  71.   menuBar = GetNewMBar (kBaseResID);//get a new menu bar
  72.   SetMenuBar (menuBar);//set the menu bar
  73.   
  74.   menu = GetMHandle (mApple);//add the Apple Menu
  75.   AddResMenu (menu, 'DRVR');//add all the Apple Menu Items
  76.   DrawMenuBar ();//draw the menu bar
  77. }
  78.  
  79. //EventLoop function - returns nothing
  80. void EventLoop (void)
  81. {
  82.   EventRecord    myEvent;//data struct to hold the Event Record returned by WNE
  83.   
  84.   do//start our main polling loop
  85.   {
  86.      if (WaitNextEvent (everyEvent, &myEvent, kSleep, 0L) )//poll for events
  87.      {
  88.        if (IsDialogEvent(&myEvent) == true)//if the event belongs to the dialog
  89.        {
  90.          HandleDialogEvent(&myEvent);//pass it to let the dialog handle it
  91.          continue;
  92.        }
  93.        else//else let the main app handle it
  94.          DoEvent (&myEvent);
  95.      }    
  96.        
  97.   }while(!global->done) ;//keep looping until the user quits
  98.   Quit();//when were done call the cleanup function
  99. }
  100.  
  101. //DoEvent function -returns nothing
  102. void DoEvent (EventRecord *eventPtr)
  103. {
  104.   char theChar;
  105.   
  106.   if (eventPtr->what==mouseDown)//check for a mouseDown event
  107.     HandleMouseDown (eventPtr);
  108.     
  109.   else  
  110.     switch (eventPtr->what)//in this program the switch() is overkill,
  111.     {                      //but if more events need to be handled,  
  112.       case keyDown:        //way to do it.
  113.       case autoKey:
  114.         theChar=eventPtr->message & charCodeMask;//set the char bit
  115.         
  116.         //checks to see if a command key modifier was pressed
  117.         if ( (eventPtr->modifiers &cmdKey) != 0)
  118.         {
  119.           long modifier = MenuKey (theChar);
  120.           HandleMenuChoice (&modifier);//menu command keys 
  121.         }
  122.         break;
  123.     }      
  124. }
  125.  
  126. //HandleMouseDown function - returns nothing
  127. void HandleMouseDown (EventRecord *eventPtr)
  128. {
  129.   WindowPtr whichWindow;
  130.   MenuHandle fileMenu;
  131.   short thePart;
  132.   long menuChoice;
  133.   
  134.   thePart = FindWindow (eventPtr->where, &whichWindow);//what window did the user click
  135.   
  136.   if (thePart==inMenuBar)//if the user clicked in the menu bar
  137.   {
  138.     fileMenu = GetMHandle (mFile);//get a handle to the file menu
  139.     if (global->dialogActive)//if there is already a dialog open
  140.       DisableItem (fileMenu, iGetInfo);//disable the menu item
  141.     else
  142.       EnableItem (fileMenu, iGetInfo);//enable the item
  143.         
  144.     menuChoice=MenuSelect (eventPtr->where);//what menu did the user choose?
  145.     HandleMenuChoice (&menuChoice);//handle the user's choice
  146.   }  
  147.   else
  148.     switch (thePart)
  149.     {
  150.       case inSysWindow://did the user click in the Finder?
  151.         SystemClick (eventPtr, whichWindow);//let the System handle it
  152.         break;
  153.           
  154.       case inDrag://let the user drag the window around the whole screen
  155.         DragWindow (whichWindow, eventPtr->where, &qd.screenBits.bounds);
  156.         break;   
  157.       }  
  158. }
  159.  
  160. //HandleMenuChoice function - returns nothing
  161. void HandleMenuChoice (long *menuChoice)
  162. {
  163.   short menu;
  164.   short item;
  165.   
  166.   if (*menuChoice != 0)
  167.   {
  168.     menu=HiWord (*menuChoice);//the menu
  169.     item= LoWord (*menuChoice);//the menu item
  170.     
  171.     switch (menu)
  172.     {
  173.       case mApple:
  174.         HandleAppleChoice (&item);
  175.         break;
  176.         
  177.       case mFile:
  178.         HandleFileChoice (&item);
  179.         break;   
  180.     }    
  181.     HiliteMenu (0);
  182.   }  
  183. }
  184.  
  185. //HandleAppleChoice function - returns nothing
  186. void HandleAppleChoice (short *item)
  187. {
  188.   MenuHandle appleMenu;
  189.   Str255 accName;
  190.   short accNumber;
  191.  
  192.   switch (*item)
  193.   {
  194.     case iAbout://this handles the whole About dialog
  195.       DialogPtr dialog;//handle to the dialog box
  196.       Handle textItemHandle;
  197.       Rect itemRect;
  198.       short itemHit, itemType, text=1;
  199.       Boolean dialogDone=false;
  200.       
  201.       dialog = GetNewDialog (kDialogResID, 0L, kMoveToFront);//load the dialog
  202.       SetPort (dialog);//set the current port to the dialog
  203.       GetDItem (dialog, text, &itemType, &textItemHandle, &itemRect);//get the only item
  204.       ShowWindow (dialog);//show the dialog
  205.       
  206.       while (!dialogDone)
  207.       {
  208.         ModalDialog (0L, &itemHit);//retrieve user item hits
  209.         if (itemHit==text)//when the user clicks in the dialog box, exit
  210.           dialogDone=true;//exit loop
  211.       }
  212.        
  213.       DisposeDialog (dialog);//free memory 
  214.       break;
  215.       
  216.     default://the user chose a DA
  217.       appleMenu=GetMHandle (mApple);
  218.       GetItem (appleMenu, *item, accName);//which App
  219.       accNumber=OpenDeskAcc (accName);
  220.       break;
  221.   }
  222. }
  223.  
  224. //HandleFileChoice function - returns nothing
  225. void HandleFileChoice (short *item)
  226. {
  227.   switch (*item)
  228.   {
  229.     case iGetInfo:
  230.       HandleEnvDialog();//show the dialog box
  231.       break;
  232.       
  233.     case iQuit:
  234.       global->done=true;//exit EventLoop
  235.       break;
  236.   }    
  237. }
  238.  
  239. //HandleEnvDialog - returns nothing
  240. void HandleEnvDialog (void)
  241. {
  242.   DialogPtr dialog;//ptr to the dialog box
  243.   Handle okItemH;
  244.   Rect itemRect;//Ok item rect
  245.   TextHandles *text = new TextHandles;//declare an instance and allocate memory
  246.   short itemType;
  247.   
  248.   dialog = GetNewDialog (kDialogResID+1, 0L, kMoveToFront);//load the dialog
  249.   SetPort (dialog);//set the port
  250.  
  251.   GetDItem (dialog, ok, &itemType, &okItemH, &itemRect);//get the button
  252.   //Get all of the text boxes we need to change
  253.   GetDItem (dialog, iSysVer, &itemType, &text->sysVerH, &itemRect);
  254.   GetDItem (dialog, iUpdateVer, &itemType, &text->updateVerH, &itemRect);
  255.   GetDItem (dialog, iMachine, &itemType, &text->machineH, &itemRect);
  256.   GetDItem (dialog, iProcessor, &itemType, &text->processorH, &itemRect);
  257.   GetDItem (dialog, iRealMem, &itemType, &text->realMemH, &itemRect);
  258.   GetDItem (dialog, iLogicalMem, &itemType, &text->logicalMemH, &itemRect);
  259.   GetDItem (dialog, iMachineID, &itemType, &text->machineIDH, &itemRect);
  260.   
  261.   GetSysEnv(&text);//get system environment
  262.   
  263.   ShowWindow (dialog);//show the dialog
  264.   global->dialogActive = true;//set the flag to de-activate the menu item
  265. }
  266.  
  267. //GetSysEnv - returns nothing
  268. void GetSysEnv (TextHandles **text)
  269. { //allocate memory for this class instance 
  270.   MachineEnv *thisMachine = new MachineEnv;
  271.   char cTempString[256];//temporary storage for C strings
  272.   Str255 *pTempString=NULL;//temporary storage for Pascal strings
  273.   
  274.   //get all of the system variables
  275.   long mySystem = thisMachine->ReturnSysVer();//get the system version
  276.   pTempString = FindSystem (&mySystem);
  277.   SetStaticString ((*text)->sysVerH, pTempString);
  278.   
  279.   long myUpdate = thisMachine->ReturnUpdateVer();//get the update version
  280.   if (mySystem>=_753)//if the system is greater than 7.5.2
  281.   {
  282.     if (myUpdate==_20)//check if it is an update
  283.       GetIndString (*pTempString, kBaseResID+3, 2);//get the udpate string
  284.     else
  285.       GetIndString (*pTempString, kBaseResID+3, 3);//get the non-udpate string
  286.   }
  287.   else
  288.     GetIndString (*pTempString, kBaseResID+3, 1);//get a error string     
  289.   SetStaticString ((*text)->updateVerH, pTempString);//set the string in the text box
  290.   
  291.   long myMachine = thisMachine->ReturnMachineType();//get the machine ID
  292.   /*sprintf() is used because the overhead of streams can not be justified for a program
  293.     of this size*/
  294.   sprintf (cTempString, "%ld", myMachine);//buffer the ID number
  295.   SetStaticString ((*text)->machineIDH, cTempString);
  296.   
  297.   pTempString = FindMachine (&myMachine, &thisMachine);//get the string to the machine
  298.   SetStaticString ((*text)->machineH, pTempString);
  299.   
  300.   long myProcessor = thisMachine->ReturnProcessor();//get the processor
  301.   pTempString = FindProcessor (&myProcessor);
  302.   SetStaticString ((*text)->processorH, pTempString);
  303.   
  304.   sprintf (cTempString, "%ld Kb", (thisMachine->ReturnRealMem()/1024));//buffer the string
  305.   SetStaticString ((*text)->realMemH, cTempString);
  306.   
  307.   sprintf (cTempString, "%ld Kb", (thisMachine->ReturnLogicalMem()/1024));//buffer the string
  308.   SetStaticString ((*text)->logicalMemH, cTempString);
  309.   
  310.   delete thisMachine;//free memory
  311. }
  312.  
  313. //FindMachine function - returns a pointer to a String resource
  314. Str255 * FindMachine (long *machineID, MachineEnv **thisMachine)
  315. {
  316.   Str255 *tempString=NULL;//holds the string if found
  317.   short whichMachine=0;//used to get the string representing the machine
  318.   Boolean performa=false;
  319.   
  320.   switch (*machineID)
  321.   { 
  322.     case gestaltPowerMac6100_60://power macs
  323.       whichMachine=i6100_60;//set the correct string number
  324.       break;
  325.       
  326.     case gestaltPowerMac7100_66:
  327.       whichMachine=i7100_66;
  328.       break;
  329.       
  330.     case gestaltPowerMac8100_80:
  331.       whichMachine=i8100_80;
  332.       break;
  333.       
  334.     case gestaltPowerMac6100_66:
  335.       whichMachine=i6100_66;
  336.       break;        
  337.     
  338.     case gestaltPowerMac7100_80:
  339.       whichMachine=i7100_80;
  340.       break;
  341.       
  342.     case gestaltPowerMac8100_100:
  343.       whichMachine=i8100_100;
  344.       break;
  345.       
  346.     case gestaltPowerMac8100_110:
  347.       whichMachine=i8100_110;
  348.       break;
  349.       
  350.     case gestaltPowerMac7200:
  351.       whichMachine=i7200;
  352.       break;
  353.       
  354.     case gestaltPowerMac7500:
  355.       if (((*thisMachine)->ReturnProcessor())==(long)gestaltCPU601)//if the CPU is a 601
  356.         whichMachine=i7500;//the machine is a 7500
  357.       else
  358.         whichMachine=i7600;//the machine is a 7600  
  359.       break;
  360.       
  361.     case gestaltPowerMac8500:
  362.       whichMachine=i8500;
  363.       break;
  364.       
  365.     case gestaltPowerMac9500:
  366.       whichMachine=i9500;
  367.       break;
  368.       
  369.     case gestaltAWS9150_80://workgroup servers
  370.       whichMachine=iAWS9150_80;
  371.       break;
  372.       
  373.     case gestaltAWS9150_120:
  374.       whichMachine=iAWS9150_120;
  375.       break;
  376.       
  377.     case gestaltPowerBookDuo2300://powerbooks
  378.       whichMachine=i2300;
  379.       break;
  380.      
  381.     case gestaltPowerBook500PPCUpgrade:
  382.       whichMachine=i500upgrade;
  383.       break;
  384.       
  385.     case gestaltPowerBook5300:
  386.       whichMachine=i5300;
  387.       break;
  388.       
  389.     case gestaltPowerMac5200://performas
  390.       whichMachine=i5200;
  391.       performa=true;
  392.       break;
  393.       
  394.     /*case gestaltPowerMac5215: I do not know the ID's of these machines,
  395.       whichMachine=i5215;       if you have one please send me the number.
  396.       performa=true;
  397.       break;
  398.       
  399.     case gestaltPowerMac6110:
  400.       whichMachine=i6110;
  401.       performa=true;
  402.       break;
  403.       
  404.     case gestaltPowerMac6112:
  405.       whichMachine=i6112;
  406.       performa=true;
  407.       break;
  408.       
  409.     case gestaltPowerMac6115:
  410.       whichMachine=i6115;
  411.       performa=true;
  412.       break;
  413.       
  414.     case gestaltPowerMac6116:
  415.       whichMachine=i6116;
  416.       performa=true;
  417.       break;
  418.       
  419.     case gestaltPowerMac6117:
  420.       whichMachine=i6117;
  421.       performa=true;
  422.       break;
  423.       
  424.     case gestaltPowerMac6118:
  425.       whichMachine=i6118;
  426.       performa=true;
  427.       break;*/
  428.       
  429.     case gestaltPowerMac6200:
  430.       whichMachine=i6200;
  431.       performa=true;
  432.       break;
  433.       
  434.    /*case gestaltPowerMac6300:  Same as above for this machine class,
  435.       whichMachine=i6300;       I need the ID number.
  436.       performa=true;
  437.       break;*/
  438.  
  439.          
  440.     default://machine is not on file
  441.       whichMachine=iNotFound;
  442.       break;  
  443.   }    
  444.   
  445.   if (!performa)//if the machine is not a peforma look in the PwrMac list
  446.     GetIndString (*tempString, kBaseResID, whichMachine);//the machine
  447.   else//look in the Performa list
  448.     GetIndString (*tempString, kBaseResID+1, whichMachine);//the performa machine  
  449.   
  450.   return tempString;
  451. }
  452.  
  453. //FindSystem function - returns a pointer to a String resource
  454. Str255 * FindSystem (long *systemVer)
  455. {
  456.   Str255 *tempString=NULL;//holds the string if found
  457.   short whichSystem=0;//used to get the string representing the machine
  458.   
  459.   switch (*systemVer)
  460.   {
  461.     case _712:// v7.1.2
  462.       whichSystem=i712;
  463.       break;
  464.       
  465.     case _750:// v7.5
  466.       whichSystem=i750;
  467.       break;
  468.       
  469.     case _751:// v7.5.1
  470.       whichSystem=i751;
  471.       break;
  472.       
  473.     case _752:// v7.5.2
  474.       whichSystem=i752;
  475.       break;
  476.               
  477.     case _753:// v7.5.3
  478.       whichSystem=i753;
  479.       break; 
  480.       
  481.     default://system is not on file
  482.       whichSystem=iSysNotFound;
  483.       break;
  484.   }
  485.    
  486.   GetIndString (*tempString, kBaseResID+2, whichSystem);//get the system string
  487.   
  488.   return tempString;
  489. }
  490.  
  491. //FindProcessor function - returns a pointer to a String resource
  492. Str255 * FindProcessor (long *processor)
  493. {
  494.   Str255 *tempString=NULL;//holds the string if found
  495.   short whichProcessor=0;//used to get the string representing the machine
  496.   
  497.   switch (*processor)
  498.   {
  499.     case gestaltCPU601:// 601
  500.       whichProcessor=i601;
  501.       break;
  502.       
  503.     case gestaltCPU603:// 603
  504.       whichProcessor=i603;
  505.       break;
  506.       
  507.     case gestaltCPU604:// 604
  508.       whichProcessor=i604;
  509.       break;
  510.       
  511.     case gestaltCPU603e://603e - defined in machines.h
  512.       whichProcessor=i603e;
  513.       break;
  514.       
  515.     case gestaltCPU604e://604e - defined in machines.h
  516.       whichProcessor=i604e;
  517.       break;      
  518.       
  519.     default:
  520.       whichProcessor=iCPUNotFound;
  521.       break;
  522.   }
  523.   
  524.   GetIndString (*tempString, kBaseResID+4, whichProcessor);//get the udpate string
  525.   
  526.   return tempString;
  527. }
  528.  
  529. //SetStaticString function (Pascal style string) - returns nothing
  530. void SetStaticString (Handle whichHandle, Str255 *tempString)
  531. {
  532.   SetHandleSize (whichHandle, (Size)*tempString[0]+1);//size the handle
  533.   HLock (whichHandle);//lock the handle
  534.   //copy the string to the field
  535.   SetIText (whichHandle, *tempString);
  536.   HUnlock (whichHandle);//unlock the handle
  537.  
  538. //SetStaticString function (C style string) - reuturns nothing
  539. void SetStaticString (Handle whichHandle, char *tempString)
  540. {
  541.   CtoPstr (tempString);//translate to a pascal string
  542.    
  543.   SetHandleSize (whichHandle, (Size)tempString[0]+1);//size the handle
  544.   HLock (whichHandle);//lock the handle
  545.   //copy the string to the field
  546.   SetIText (whichHandle, (const unsigned char *)tempString);
  547.   HUnlock (whichHandle);//unlock the handle
  548.  
  549. //HandleDialogEvent function - returns nothing
  550. void HandleDialogEvent(EventRecord *eventPtr)
  551. {
  552.   DialogPtr   dialog = (DialogPtr)FrontWindow();
  553.   GrafPtr     origPort;
  554.   short       myItem;
  555.  
  556.   GetPort(&origPort);//store the original port
  557.   SetPort(dialog);//then set the port to the dialog
  558.  
  559.   if (EventFilter(eventPtr, dialog) != false)//run through our filter
  560.   {
  561.     if (DialogSelect(eventPtr, &dialog, &myItem) == true)//if our button was clicked
  562.     {
  563.       if (dialog != 0L)//if the dialog is not NULL
  564.       { 
  565.         switch (myItem)
  566.         {
  567.           case ok://if ok was hit doing the switch, just dispose of the dialog
  568.             //Internal error handiling, not needed in the Final
  569.             //HandleError(0, false, "\pDestroying Dialog");
  570.             DisposeDialog (dialog);//free memory
  571.             global->dialogActive = false;//then set the flag to show the menu item
  572.             break;       
  573.         }
  574.       }
  575.     }
  576.   }
  577.   SetPort (origPort);//restore the original port
  578. }
  579.  
  580. //EventFilter function - returns a Boolean value
  581. Boolean EventFilter(EventRecord *myEvent, WindowPtr myFrontWindow)
  582. {
  583.   short ok=1;
  584.   
  585.   switch (myEvent->what)
  586.   {
  587.     case activateEvt://if it is an activate event               
  588.       //Take care of hiliting the
  589.       //Ok button according to whether or not the dialog is in front.
  590.       myFrontWindow = (WindowPtr)myEvent->message;
  591.       
  592.       ControlHandle okHandle = GetCtlHandle((DialogPtr)myFrontWindow, ok);
  593.       if ((myEvent->modifiers & activeFlag) == true)
  594.         HiliteControl(okHandle, 0);//if we are active
  595.       else
  596.         HiliteControl(okHandle, 255);//if we are in the background
  597.  
  598.       return false;
  599.       break;
  600.    }
  601.    
  602.    return true;//if no events were processed return true
  603.  }     
  604.  
  605. //GetCtlHandle function - returns a Handle to a control item
  606. static ControlHandle GetCtlHandle(DialogPtr dialog, short item)
  607. {
  608.     Handle  myControl;
  609.     short   itemType;
  610.     Rect    itemRect;
  611.     
  612.     GetDItem(dialog, item, &itemType, &myControl, &itemRect);//get the handle
  613.     if (myControl == 0L)//if the handle is null
  614.         HandleError(3, true, 0L);//call our error handling code
  615.  
  616.     return (ControlHandle)myControl;//return the handle
  617. }
  618.  
  619. //HandleError function - returns nothing
  620. void HandleError (short stringID, Boolean fatal, Str255 debugStr)
  621. {
  622.   Str255 errStr;
  623.   Str15 fatalStr;
  624.   short itemHit;
  625.     
  626.   //set the cursor back to the arrow, could check for what the cursor is,
  627.   //but this won't hurt
  628.   SetCursor (&qd.arrow);
  629.   
  630.   if (fatal && !debugStr)//if the error is fatal, and not a debug string
  631.   {
  632.     GetIndString (fatalStr, kErrorStringsID, 1);//get the notification string
  633.     GetIndString (errStr, kErrorStringsID, stringID);//get the error string
  634.     ParamText (fatalStr, errStr, "\p ", "\p ");//set the paramter strings
  635.   }  
  636.   else
  637.     if (!fatal && !debugStr)//if the error is not fatal, and not a debug string
  638.     {
  639.       GetIndString (errStr, kErrorStringsID, stringID);//get the error string
  640.       ParamText (errStr, "\p ", "\p ", "\p ");//set the paramter strings
  641.     }
  642.     else
  643.       if (debugStr)//if it is just a debug string
  644.         ParamText (debugStr, "\p ", "\p ", "\p ");//set the paramter strings
  645.         
  646.   if (fatal)//if this is a fatal error
  647.   {          
  648.     itemHit = StopAlert (kAlertID, 0L);//alert user
  649.     Quit();//then exit right away
  650.   }
  651.   else//warn the user
  652.     itemHit = CautionAlert (kAlertID, 0L);//alert user
  653. }
  654.  
  655. //Quit function - returns nothing
  656. inline void Quit (void)
  657. {  
  658.   //Internal error handiling, not needed in the Final
  659.   //HandleError(0, false, "\pDeleting global struct 'AppGlobals'.");
  660.   delete global;//free the global memory before we quit
  661.   ExitToShell();//then exit
  662. }      
  663.  
  664.  
  665.           
  666.  
  667.        
  668.